package com.novellotus.iov.carvice.model;

import android.content.Context;
import android.os.Bundle;
import android.os.Message;

import com.novellotus.iov.carvice.bean.MqttListCarBean;
import com.novellotus.iov.carvice.bean.MqttSingleCarStatue;
import com.novellotus.iov.carvice.bean.MqttVehicleBean;
import com.novellotus.iov.carvice.retrofit.RetrofitFactory;
import com.novellotus.iov.carvice.utils.GetJsonDataUtil;
import com.novellotus.iov.carvice.utils.HandlerUtils;
import com.novellotus.iov.carvice.utils.MyUtils;
import com.novellotus.iov.carvice.utils.SharedPreferencesUtils;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Created by Rich on 2017/6/7.
 * mqtt封装类
 */
public class MqttModule implements HandlerUtils.OnReceiveMessageListener {

    private Context context;
    //private String host = "tcp://192.168.1.20:1883";
    private String host;
    private String userName = "";
    private String passWord = "";
   // private MyHandle handler;
    private MqttClient client;
    //mqtt主题
    private String myTopic[];
    private MqttConnectOptions options;
    private ScheduledExecutorService scheduler;
    private MyRunnable myRunnable;
    private Thread thread;
    private MySchedulerRunnable mySchedulerRunnable;
    private MqttMessageInterface mqttMessageInterface;
    private int topicType;//0车辆列表主题 1单车主题 2单车和状体主题
    private HandlerUtils.HandlerHolder handlerHolder;

    public MqttModule(Context context, MqttMessageInterface mqttMessageInterface, String name, String password) {
        this.context = context;
        this.mqttMessageInterface = mqttMessageInterface;
      //  handler = new MyHandle();
        userName = name;
        passWord = password;
        init();
    }

    /**
     * @param myTopic 设置主题
     */
    public void setTop(String myTopic[], int topicType) {
        this.myTopic = myTopic;
        this.topicType = topicType;
    }

    /**
     * 初始化mqtt设置
     */
    public void init() {
        handlerHolder=new HandlerUtils.HandlerHolder(this);
        host = RetrofitFactory.host;
        try {
            //host为主机名，test为clientid即连接MQTT的客户端ID，一般以客户端唯一标识符表示，MemoryPersistence设置clientid的保存形式，默认为以内存保存
            client = new MqttClient(host, SharedPreferencesUtils.getKey(context)[2] + System.currentTimeMillis(), new MemoryPersistence());
            //MQTT的连接设置
            options = new MqttConnectOptions();
            //设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录，这里设置为true表示每次连接到服务器都以新的身份连接
            options.setCleanSession(true);
            //设置连接的用户名
            options.setUserName(userName);
            //设置连接的密码
            options.setPassword(passWord.toCharArray());
            // 设置超时时间 单位为秒
            options.setConnectionTimeout(30);
            // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线，但这个方法并没有重连的机制
            options.setKeepAliveInterval(30);
            options.setCleanSession(true);
            //设置回调
            client.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable cause) {
                    connect();
                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
                    //publish后会执行到这里
                    MyUtils.logInformation("mqtt" + "关闭连接: ");
                }

                @Override
                public void messageArrived(String topicName, MqttMessage message)
                        throws Exception {
                    //subscribe后得到的消息会执行到这里面
                    int topType;//0是状态 1是整车
                    MyUtils.logInformation("主题:" + topicName);
                    if (topicName.contains("follow_vehicles")) {
                        MyUtils.logInformation("是状态主题");
                        topType = 0;
                    } else {
                        MyUtils.logInformation("是整车主题");
                        topType = 1;
                    }
                    Message msg = new Message();
                    msg.what = 1;
                    Bundle bundle = new Bundle();
                    String[] arrString = topicName.split("/");
                    bundle.putString("vin", arrString[arrString.length - 1]);
                    bundle.putString("data", message.toString());
                    bundle.putInt("topType", topType);
                    msg.setData(bundle);
                    handlerHolder.sendMessage(msg);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 连接mqtt
     */
    private void connect() {
        myRunnable = new MyRunnable();
        thread = new Thread(myRunnable);
        thread.start();
    }

    /**
     * 连接mqtt
     */
    public void startReconnect() {
        scheduler = Executors.newSingleThreadScheduledExecutor();
        mySchedulerRunnable = new MySchedulerRunnable();
        //使用周期性重连机制
        scheduler.scheduleAtFixedRate(mySchedulerRunnable, 0 * 1000, 10 * 1000, TimeUnit.MILLISECONDS);
    }

    @Override
    public void handlerMessage(Message msg) {
        switch (msg.what) {
            case 1:
                String data = msg.getData().getString("data");
                String vin = msg.getData().getString("vin");
                int topType = msg.getData().getInt("topType");

                if (msg.getData().getString("data") != null) {
                    MyUtils.logInformation("topicType:" + topicType);
                    try {
                        //      MyUtils.logInformation("MQTT消息:" + data);
                        //  MyUtils.logInformation("vin:" + vin);
                        MqttListCarBean mqttListCarBean;
                        MqttVehicleBean mqttVehicleBean;
                        if (topicType == 0) {
                            mqttListCarBean = GetJsonDataUtil.parseJsonWithGson(data, MqttListCarBean.class);
                            mqttMessageInterface.getTopic(mqttListCarBean, null, vin);
                        } else if (topicType == 1) {
                            mqttVehicleBean = GetJsonDataUtil.parseJsonWithGson(data, MqttVehicleBean.class);
                            mqttMessageInterface.getTopic(null, mqttVehicleBean, vin);
                        } else if (topicType == 2) {
                            if (topType == 0) {
                                MyUtils.logInformation("状态消息:" + data);
                                MqttSingleCarStatue mqttSingleCarStatue = GetJsonDataUtil.parseJsonWithGson(data, MqttSingleCarStatue.class);
                                mqttMessageInterface.getSingleCarStatue(mqttSingleCarStatue);
                            } else {
                                MyUtils.logInformation("整车消息:" + data);
                                mqttVehicleBean = GetJsonDataUtil.parseJsonWithGson(data, MqttVehicleBean.class);
                                mqttMessageInterface.getTopic(null, mqttVehicleBean, vin);
                            }
                        }

                    } catch (Exception e) {
                        MyUtils.logInformation(e.toString());
                    }
                }
                break;
            case 2:
                MyUtils.logInformation("mqtt-" + "连接成功: ");
                try {
                    client.subscribe(myTopic);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            case 3:
                MyUtils.logInformation("mqtt-" + "连接异常 ");
                break;
        }
    }


    /**
     * 重连机制:周期性检查mqtt链接状态
     */
    private class MySchedulerRunnable implements Runnable {
        @Override
        public void run() {
            //如果当前不是连接状态则重新连接
            if (!client.isConnected()) {
                MyUtils.logInformation("断开了，需要重连");
                connect();
            } else {
                MyUtils.logInformation("链接中，不用重连");
            }
        }
    }

    /**
     * 轮询线程
     * 2.s
     */
    private class MyRunnable implements Runnable {
        @Override
        public void run() {
            try {
                if (client != null && !client.isConnected()) {
                    client.connect(options);
                    handlerHolder.sendEmptyMessage(2);
                }

            } catch (Exception e) {
                e.printStackTrace();
                if (handlerHolder != null) {
                    handlerHolder.sendEmptyMessage(3);
                }
            }
        }
    }


    /**
     * 停止mqtt连接
     */
    public void stopConnect() {
        closeMqtt();
    }

    /**
     * 关闭mqtt
     * 切换页面时关闭mqtt连接
     */
    public void closeMqtt() {
        try {
            MyUtils.logInformation("mqtt" + "关闭连接: ");
            if (client != null && client.isConnected()) {
                client.disconnect();
            }
            if (scheduler != null && !scheduler.isShutdown()) {
                scheduler.shutdown();
            }
            myRunnable = null;
            thread = null;
            mySchedulerRunnable = null;
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }



    /**
     * 重新设置订阅主题
     */
    public void setTopic() {
        try {
            client.subscribe(myTopic);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }


    /**
     * 销毁mqtt
     * 释放资源等待GC
     */
    public void destroyModule() {
        try {
            if (scheduler != null) {
                scheduler.shutdown();
            }

            if (client != null && client.isConnected()) {
                client.disconnect();
            }
            handlerHolder = null;
            client = null;
            myTopic = null;
            options = null;
            myRunnable = null;
            thread = null;
            context = null;
            mqttMessageInterface = null;
        } catch (MqttException e) {
            e.printStackTrace();
        }
        System.gc();
    }


    /**
     * 收到消息后通知activity
     */
    public interface MqttMessageInterface {
        void getTopic(MqttListCarBean mqttListCarBean, MqttVehicleBean mqttVehicleBean, String vin);
        void getSingleCarStatue(MqttSingleCarStatue mqttSingleCarStatue);
    }

}
